#include "uart.h"
#include "lpc24xx.h"
#include "type.h"
#include "sdram.h"
#include <string.h>
#include <stdio.h>
#include "debug_settings.h"

void delay(void )
{
	volatile int i,j;

	for (i=0;i<2000;i++)
		for (j=0;j<100;j++);
}

void SDRAM_init(void) {
	DWORD i, dummy = dummy;
#if DEBUG_SDRAM
	xprintf("In function initSDRAM()...\n");
#endif
	//SDRAM initialization

	//Step 1.  Set the PCEMC bit in PCONP register to 1 to enable the external memory controller. It's already 1 upon reset, but I'll do it anyway.
	PCONP |= 0x00000800;
	
	//Step 2. Ensure CPU clock is already set up.  It is.
	
	// Step 2.5... EMC_CTRL
	EMC_CTRL = 0x00000001;	 /*Disable Address mirror... not sure if we have to do this... */

	//Step 3. Set data, address and control pins. in PINSEL6/8/9 and PINMODE6/8/9
	/* 	PINSEL5: 
	[1:0]	01	CAS
	[3:2]	01	RAS
	[5:4]	01	CLKOUT0
	[9:8]	01	DYCS0
	[17:16]	01	CKEOUT0
	[25:24]	01	DQMOUT0
	[27:26]	01	DQMOUT1
	Hex representation:
	[31 30 29 28] [27 26 25 24] [23 22 21 20] [19 18 17 16] [15 14 13 12] [11 10 9 8] [7 6 5 4] [3 2 1 0]
	[0   0  0  0] [0  1   0  1] [0   0  0  0] [0  0   0  1] [0   0  0  0] [ 0  0 0 1] [0 0 0 1] [0 1 0 1]
	*/
	
	PINSEL5=0x05010115;
	
	/*	PINSEL6:
	Enable D0-D15
	All pins 01... all hex values 0101... all 5's.
	*/
	PINSEL6=0x55555555;//enable Data lines (D0-D15) (P3[0] - P3[15])
	
	/*	PINSEL8:
	Enable A0-A14... all but MSB.
	*/
	PINSEL8=0x15555555;//enable address lines (A0-A14) (P4[0] - P4[14])
	
	/*	PINSEL9:
	[19:18] 01	WE
	*/
	PINSEL9=0x00040000;//enable WE (P4[25])

	//now lets set all the pin modes to indicate that none of these SDRAM pins have neither pull up nor pull down resistors on them)
	PINMODE5=0x0A02022A; //DQMOUT1, DQMOUT0, CKEOUT0, DYCS0, CLKOUT0, RAS, CAS
	PINMODE6=0xAAAAAAAA; //data lines
	PINMODE8=0x2AAAAAAA; //address lines
	PINMODE9=0x00080000; //WE

	/*
	 * Above is our set up -M. Hardee
	 * Below is the example code.
	 */
	  EMC_DYN_RP     = 2;		/* command period: 3(n+1) clock cycles */
	  EMC_DYN_RAS    = 3;		/* RAS command period: 4(n+1) clock cycles */
	  EMC_DYN_SREX   = 7;		/* Self-refresh period: 8(n+1) clock cycles */
	  EMC_DYN_APR    = 2;		/* Data out to active: 3(n+1) clock cycles */
	  EMC_DYN_DAL    = 5;		/* Data in to active: 5(n+1) clock cycles */
	  EMC_DYN_WR     = 1;		/* Write recovery: 2(n+1) clock cycles */
	  EMC_DYN_RC     = 5;		/* Active to Active cmd: 6(n+1) clock cycles */
	  EMC_DYN_RFC    = 5;		/* Auto-refresh: 6(n+1) clock cycles */
	  EMC_DYN_XSR    = 7;		/* Exit self-refresh: 8(n+1) clock cycles */
	  EMC_DYN_RRD    = 1;		/* Active bank A->B: 2(n+1) clock cycles */
	  EMC_DYN_MRD    = 2;		/* Load Mode to Active cmd: 3(n+1) clock cycles */

	  EMC_DYN_RD_CFG = 1;		/* Command delayed strategy */

	  /* Default setting, RAS latency 3 CCLKs, CAS latenty 3 CCLKs. */
	  EMC_DYN_RASCAS0 = 0x00000303;

	  /* 256MB, 16Mx16, 4 banks, row=13, column=9
	   * [4:3] = 00 (SDRAM, not low power SDRAM or Micron SyncFlash.)
	   * [12:7] address mapping: 16Mx16 256MB:
	          [14]: 0
			  [12]: 0
			  [11:9]: 011
			  [8:7]: 01
		* Buffer must be disabled during initialization...
		* must be enabled during normal operation.
		* [19]: buffer disable: 0
		* [20]: write protect... 0 off
	  
	  [31 30 29 28] [27 26 25 24] [23 22 21 20] [19 18 17 16] [15 14 13 12] [11 10 9 8] [7 6 5 4] [3 2 1 0]
	  [0   0  0  0] [0  0   0  0] [0   0  0  0] [0  0   0  0] [0   0  0  0] [ 0  1 1 0] [1 0 0 0] [0  0 00]
	  0x00000680
	  */

	  EMC_DYN_CFG0 = 0x00000680;

	  delay();

	  /* Mem clock enable, CLKOUT runs, send command: NOP */
	  EMC_DYN_CTRL = 0x00000183;
	  delay();

	  /* Send command: PRECHARGE-ALL, shortest possible refresh period */
	  EMC_DYN_CTRL = 0x00000103;

	  /* set 32 CCLKs between SDRAM refresh cycles */
	  EMC_DYN_RFSH = 0x00000002;
	  for(i = 0; i < 0x40; i++);	/* wait 128 AHB clock cycles */

	  /* set 28 x 16CCLKs=448CCLK=7us between SDRAM refresh cycles */
	  EMC_DYN_RFSH = 28;

	  /* To set mode register in SDRAM, enter mode by issue
	  MODE command, after finishing, bailout and back to NORMAL mode. */
	  /* Mem clock enable, CLKOUT runs, send command: MODE */
	  EMC_DYN_CTRL = 0x00000083;

	  /* Set mode register in SDRAM */
	  /* Mode regitster table for Micron's MT48LCxx */
	  /* bit 9:   Programmed burst length(0)
	     bit 8~7: Normal mode(0)
		 bit 6~4: CAS latency 3
		 bit 3:   Sequential(0)
		 bit 2~0: Burst length is 8
		 row position is 12 */
	  dummy = *((volatile DWORD *)(SDRAM_BASE_ADDR | (0x33 << 12)));

	  EMC_DYN_CTRL = 0x00000000;	  /* Send command: NORMAL */

	  EMC_DYN_CFG0 |= 0x00080000;	  /* Enable buffer */
	  delay();				  /* Use timer 1 */

#if DEBUG_SDRAM
	  xprintf("Exiting SDRAMinit()...\n");
#endif

	return;
}


// SHORT test
int SDRAM_test_word(void) {
		volatile WORD *short_wr_ptr;
		DWORD i;

		/* Maximum for test purposes.
		 * unsigned short [WORD] ranges from 0-65535
		 * unsigned long [DWORD] ranges from 0-4294967295
		 */

		DWORD MAX_TEST;

		/* Quick note:
		 * SDRAM_SIZE = 0x2000000 = 33554432 bytes = 32 megabytes
		 * Each WORD (unsigned short) is 2 bytes.
		 * That means we can put 16M words into our SDRAM (or SDRAM_SIZE / 2).
		 */
		MAX_TEST = (DWORD) (SDRAM_SIZE/2);

		short_wr_ptr = (WORD *)SDRAM_BASE_ADDR;

		/* Populate SDRAM */
		xprintf("Filling from Word#0 to Word#%d...\n", MAX_TEST);

		/* We could have:
		 * for(i=0; i < SDRAM_SIZE/2; i++)
		 * to fill the whole SDRAM but I only go to 1000 so
		 * the test doesn't take very long to complete.
		*/
		for(i=0; i < MAX_TEST; i++) {

				/* Print debug messages */
				/*
				uprintfx_word( i ); // This prints a WORD-sized hex representation of a WORD to UART.
				xprintf(" gets ");
				uprintfx_word( i );
				xprintf("\n");
				*/

				/* Print status */

				if(i == 0) {
					xprintf("0%...");
				}
				else if(i == ((MAX_TEST)/4)) {
					xprintf("25%...");
				}
				else if(i == ((MAX_TEST)/2)) {
					xprintf("50%...");
				}
				else if(i == (((MAX_TEST)/4)*3)) {
					xprintf("75%...");
				}


				/* Write to SDRAM */
				*short_wr_ptr++ = (WORD) i;
		}
		xprintf("ok!\n\n");

		/* Verify
		   Put pointer back to beginning of SDRAM */
		xprintf("Verifying (entering loop)... ");

		short_wr_ptr = (WORD *)SDRAM_BASE_ADDR;

		for(i=0; i < MAX_TEST; i++) {

			/* Read WORD from SDRAM location */
			WORD temp = *short_wr_ptr++;

			/* Print status */

			if(i == 0) {
				xprintf("0%...");
			}
			else if(i == ((MAX_TEST)/4)) {
				xprintf("25%...");
			}
			else if(i == ((MAX_TEST)/2)) {
				xprintf("50%...");
			}
			else if(i == (((MAX_TEST)/4)*3)) {
				xprintf("75%...");
			}

			/* Compare. */
			/* If success */
			if(temp == (WORD) i) {
				/*
				xprintf("Success at ");
				uprintfx_dword(i);
				xprintf("! (Got ");
				uprintfx_word(temp);
				xprintf(")\n");
				*/
			}

			/* If failure */
			else {
				xprintf("Failure at %d: %04x\n", i, temp);
			}

		}

		xprintf("\n***** Done with test! *****\n");
		return 1;
}

// DWORD test
int SDRAM_test_dword(void) {
		volatile DWORD *dword_wr_ptr;
		DWORD i;

		/* Maximum for test purposes.
		 * unsigned short [WORD] ranges from 0-65535
		 * unsigned long [DWORD] ranges from 0-4294967295
		 */

		DWORD MAX_TEST;

		/* Quick note:
		 * SDRAM_SIZE = 0x2000000 = 33554432 bytes = 32 megabytes
		 * Each DWORD (unsigned long) is 4 bytes.
		 * That means we can put 8M words into our SDRAM (or SDRAM_SIZE / 4)
		 */
		MAX_TEST = (DWORD) (SDRAM_SIZE/4);

		dword_wr_ptr = (DWORD *)SDRAM_BASE_ADDR;

		/* Populate SDRAM */
		xprintf("Filling from DWORD#0 to DWORD#");
		uprintfi((int) MAX_TEST);
		xprintf("...\n");

		xprintf("Or from SDRAM[");
		uprintfx_dword((DWORD) 0);
		xprintf("] to SDRAM[");
		uprintfx_dword((DWORD) MAX_TEST);
		xprintf("]\n");

		/* We could have:
		 * for(i=0; i < SDRAM_SIZE/2; i++)
		 * to fill the whole SDRAM but I only go to 1000 so
		 * the test doesn't take very long to complete.
		*/
		for(i=0; i < MAX_TEST; i++) {

				/* Print debug messages */
				/*
				uprintfx_word( i ); // This prints a WORD-sized hex representation of a WORD to UART.
				xprintf(" gets ");
				uprintfx_word( i );
				xprintf("\n");
				*/

				/* Print status */

				if(i == 0) {
					xprintf("0%...");
				}
				else if(i == ((MAX_TEST)/4)) {
					xprintf("25%...");
				}
				else if(i == ((MAX_TEST)/2)) {
					xprintf("50%...");
				}
				else if(i == (((MAX_TEST)/4)*3)) {
					xprintf("75%...");
				}


				/* Write to SDRAM */
				*dword_wr_ptr++ = i;
		}
		xprintf("ok!\n\n");

		/* Verify
		   Put pointer back to beginning of SDRAM */
		xprintf("Verifying (entering loop)... ");

		dword_wr_ptr = (DWORD *)SDRAM_BASE_ADDR;

		for(i=0; i < MAX_TEST; i++) {

			/* Read WORD from SDRAM location */
			DWORD temp = *dword_wr_ptr++;

			/* Print status */

			if(i == 0) {
				xprintf("0%...");
			}
			else if(i == ((MAX_TEST)/4)) {
				xprintf("25%...");
			}
			else if(i == ((MAX_TEST)/2)) {
				xprintf("50%...");
			}
			else if(i == (((MAX_TEST)/4)*3)) {
				xprintf("75%...");
			}

			/* Compare. */
			/* If success */
			if(temp == i) {
				/*
				xprintf("Success at ");
				uprintfx_dword(i);
				xprintf("! (Got ");
				uprintfx_word(temp);
				xprintf(")\n");
				*/
			}

			/* If failure */
			else {
				xprintf("Failure at ");
				uprintfx_dword(i);
				xprintf(": ");
				uprintfx_dword(temp);
				xprintf("\n");
			}

		}

		xprintf("\n***** Done with test! *****\n");
		return 1;
}

// DWORD test
int SDRAM_test_byte(void) {
		volatile BYTE *byte_wr_ptr;
		DWORD i;

		/* Maximum for test purposes.
		 * unsigned short [WORD] ranges from 0-65535
		 * unsigned long [DWORD] ranges from 0-4294967295
		 */

		DWORD MAX_TEST;

		/* Quick note:
		 * SDRAM_SIZE = 0x2000000 = 33554432 bytes = 32 megabytes
		 * Each BYTE (char) is 1 byte.
		 * That means we can put 32M bytes into our SDRAM (or SDRAM_SIZE)
		 */
		MAX_TEST = (DWORD) (SDRAM_SIZE);

		byte_wr_ptr = (BYTE *)SDRAM_BASE_ADDR;

		/* Populate SDRAM */
		xprintf("Filling from BYTE #0 to BYTE #%d...\n", MAX_TEST);
		xprintf("Or from SDRAM address 0x00000000 to SDRAM address %08x.\n", MAX_TEST);


		for(i=0; i < MAX_TEST; i++) {

				/* Print debug messages */
				/*
				uprintfx_word( i ); // This prints a WORD-sized hex representation of a WORD to UART.
				xprintf(" gets ");
				uprintfx_word( i );
				xprintf("\n");
				*/

				/* Print status */

				if(i == 0) {
					xprintf("0%...");
				}
				else if(i == ((MAX_TEST)/4)) {
					xprintf("25%...");
				}
				else if(i == ((MAX_TEST)/2)) {
					xprintf("50%...");
				}
				else if(i == (((MAX_TEST)/4)*3)) {
					xprintf("75%...");
				}


				/* Write to SDRAM */
				*byte_wr_ptr++ = (BYTE) i;
		}
		xprintf("ok!\n\n");

		/* Verify
		   Put pointer back to beginning of SDRAM */
		xprintf("Verifying (entering loop)... ");

		byte_wr_ptr = (BYTE *)SDRAM_BASE_ADDR;

		for(i=0; i < MAX_TEST; i++) {

			/* Read WORD from SDRAM location */
			BYTE temp = *byte_wr_ptr++;

			/* Print status */

			if(i == 0) {
				xprintf("0%...");
			}
			else if(i == ((MAX_TEST)/4)) {
				xprintf("25%...");
			}
			else if(i == ((MAX_TEST)/2)) {
				xprintf("50%...");
			}
			else if(i == (((MAX_TEST)/4)*3)) {
				xprintf("75%...");
			}

			/* Compare. */
			/* If success */
			if(temp == (BYTE) i) {
				/*
				xprintf("Success at ");
				uprintfx_dword(i);
				xprintf("! (Got ");
				uprintfx_word(temp);
				xprintf(")\n");
				*/
			}

			/* If failure */
			else {
				xprintf("Failure at %08x: %02x\n", i, temp);
			}

		}

		xprintf("\n***** Done with test! *****\n");
		return 1;
}
